const express = require("express");
const fs = require("fs");
const path = require("path");
const Module = require("module");
const cookieParser = require('cookie-parser');
const { createStaticProxy } = require("./serverUtils/staticProxyUtil.js");
const PORT = parseInt(process.env.PORT, 10) || 3000;
const isEnvProduction = process.env.NODE_ENV === "production";
const isEnvDevelopment = process.env.NODE_ENV === "development";
const app = express();
// 禁用标头，可以防止一些攻击者获取更多信息
app.disable('x-powered-by');

(async () => {
	// 初始化数据与状态
	let compiling = Promise.resolve();
	let manifest;
	const compilingList = [];
	// 编译时阻塞请求
	app.use((req, res, next) => compiling.then(next));
	// 对外只暴露public文件夹
	app.use(['/favicon.ico'], createStaticProxy('public'));
	// 将public文件夹作为静态资源目录，缓存时间为一年
	app.use("/public", express.static("./public", { maxAge: 365 * 24 * 3600 * 1000 }));

	console.log("开始创建服务...");
	let serverRender = () => "loading...";
	let middleware = {};
	const devCompileCallBack = (serverBound, clientManifest) => {
		try {
			if (serverBound) {
				console.log("更新服务端代码");
				const module_server = new Module("module_server");
				module_server._compile(serverBound, "serverEntry");
				const renderEntry = module_server.exports;
				serverRender = renderEntry.serverRender;
				middleware = renderEntry.middleware;
			}
			if (clientManifest) {
				console.log("更新客户端代码");
				manifest = JSON.parse(clientManifest);
			}
		} catch (e) {
			console.error(e);
		}
	};

	// 开发环境
	if (isEnvDevelopment) {
		const devCompiler = (await import("./dev-compiler.js")).default;
		try {
			await devCompiler(
				app,
				devCompileCallBack,
				() => {
					compiling = new Promise(resolve => compilingList.push(resolve));
				},
				() => {
					while (compilingList.length) compilingList.shift()();
				}
			);
		} catch (error) {
			console.error(error);
		}
		console.log("webpack初始化完成");
	}

	// 生产环境
	if (isEnvProduction) {
		const renderEntry = await import("../src/entry-server");
		serverRender = renderEntry.serverRender;
		manifest = JSON.parse(fs.readFileSync("./client-manifest.json", "utf8"));
	}


	// 中间件
	// 干掉 404 的 .map 请求, 防止污染日志
	app.use(/\/public\/.+\.map$/, (req, res, next) => res.status(404).end());
	// cookie中间件
	app.use(cookieParser())
	// 记录日志
	app.use((...e) => middleware.logger(...e))
	// debug 
	app.use((...e) => middleware.debugInject(...e))
	// 服务端初始化数据
	app.use((...e) => middleware.initData(...e));
	// 分析请求类型
	app.use((...e) => middleware.analyzeRequestType(...e));
	// 服务端匹配路由
	app.use((...e) => middleware.analyzeRouteStatus(...e));
	// 服务端页面缓存分析
	// xxx
	// 访问页面服务端的渲染逻辑
	app.get("*", async (req, res) => {
		try {
			let template = fs.readFileSync(path.resolve(__dirname, "../public/index.html"), "utf-8");
			serverRender({ options: { template, manifest }, req, res });
		} catch (e) {
			console.error(e);
			res.status(404).send(isEnvProduction ? null : `<div style="white-space: pre">${e.toString() === "[object Object]" ? JSON.stringify(e, null, "\t") : e.stack || e}</div>`);
		}
	});

	app.listen(PORT, () => {
		console.log(`服务已启动: http://127.0.0.1:${PORT}`);
	});
})();
